#include "base.h"
#include "napi/native_api.h"
#include <cstring>
#include <exception>

#ifndef HAR_PAGE_INFO_H
#define HAR_PAGE_INFO_H
struct PageInfoCallbackData {
    napi_async_work asyncWork;
    napi_deferred deferred;
    napi_ref callback;
    uint32_t in_index;
    uint32_t in_scale;
    uint32_t in_samples;
    int out_data_len;
    int out_width;
    int out_height;
    int out_dpi;
    char *out_buffer;
};

static void PageInfoExecute(napi_env env, void *data) {
    try {
        PageInfoCallbackData *callbackData = reinterpret_cast<PageInfoCallbackData *>(data);
        ddjvu_page_t *page = ddjvu_page_create_by_pageno(document, callbackData->in_index);
        if (page != NULL) {
            ddjvu_job_t *job = ddjvu_page_job(page);
            while (ddjvu_job_status(job) < DDJVU_JOB_OK) {
                handle_message();
            }
            if (ddjvu_job_status(job) < DDJVU_JOB_FAILED) {
                callbackData->out_width = ddjvu_page_get_width(page);
                callbackData->out_height = ddjvu_page_get_height(page);
                callbackData->out_dpi = ddjvu_page_get_resolution(page);
                ddjvu_format_style_t style = callbackData->in_samples == 1 ? DDJVU_FORMAT_GREY8 : DDJVU_FORMAT_RGB24;
                ddjvu_format_t *fmt = ddjvu_format_create(style, 0, NULL);
                if (fmt != NULL) {
                    ddjvu_format_set_row_order(fmt, 1);
                    ddjvu_format_set_y_direction(fmt, 1);
                    ddjvu_rect_t rect;
                    rect.x = 0;
                    rect.y = 0;
                    rect.w = callbackData->in_scale * callbackData->out_width;
                    rect.h = callbackData->in_scale * callbackData->out_height;
                    int row_size = callbackData->in_samples * rect.w;
                    int data_len = row_size * rect.h;
                    char *buffer = new char[data_len];
                    ddjvu_page_render(page, DDJVU_RENDER_COLOR, &rect, &rect, fmt, row_size, buffer);
                    ddjvu_job_t *job = ddjvu_page_job(page);
                    while (ddjvu_job_status(job) < DDJVU_JOB_OK) {
                        handle_message();
                    }
                    ddjvu_format_release(fmt);
                    if (ddjvu_job_status(job) < DDJVU_JOB_FAILED) {
                        callbackData->out_data_len = data_len;
                        callbackData->out_buffer = buffer;
                    }
                }
            }
        }
    } catch (std::exception &e) {
    }
}

static void PageInfoComplete(napi_env env, napi_status status, void *data) {
    PageInfoCallbackData *callbackData = reinterpret_cast<PageInfoCallbackData *>(data);
    napi_value result;
    napi_create_object(env, &result);
    // width
    napi_value width_key;
    napi_value width_value;
    napi_create_string_utf8(env, "width", NAPI_AUTO_LENGTH, &width_key);
    napi_create_int32(env, callbackData->out_width, &width_value);
    napi_set_property(env, result, width_key, width_value);
    // height
    napi_value height_key;
    napi_value height_value;
    napi_create_string_utf8(env, "height", NAPI_AUTO_LENGTH, &height_key);
    napi_create_int32(env, callbackData->out_height, &height_value);
    napi_set_property(env, result, height_key, height_value);
    // dpi
    napi_value dpi_key;
    napi_value dpi_value;
    napi_create_string_utf8(env, "dpi", NAPI_AUTO_LENGTH, &dpi_key);
    napi_create_int32(env, callbackData->out_dpi, &dpi_value);
    napi_set_property(env, result, dpi_key, dpi_value);
    // pixel
    void *buffer_ptr = nullptr;
    napi_value array_buffer;
    napi_create_arraybuffer(env, callbackData->out_data_len, &buffer_ptr, &array_buffer);
    memcpy(buffer_ptr, callbackData->out_buffer, callbackData->out_data_len);
    napi_value pixel_key;
    napi_create_string_utf8(env, "pixel", NAPI_AUTO_LENGTH, &pixel_key);
    napi_set_property(env, result, pixel_key, array_buffer);
    napi_resolve_deferred(env, callbackData->deferred, result);
    napi_delete_async_work(env, callbackData->asyncWork);
    delete callbackData;
}
#endif
